﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////


#pragma once
#include "GnufObjectPtr.h"

class QWidget;

namespace gnuf {
    
    class ArrangementArea;
    class ArrangementAreaEvent;
    class LayoutComputer;
    class DragMove;
    class ScaleFactor;
    
    class GNUF_BASE_EXPORT ArrangementAreaContent
    {
        DEFINE_CAST_BASE(ArrangementAreaContent)
        GNUF_WATCHABLE_OBJECT(ArrangementAreaContent) ///< use gcmp::ObjectWeakPtr to wrap

    protected:
        ArrangementAreaContent(const std::wstring &);
    public:
        virtual ~ArrangementAreaContent();
        
    public:
        const std::wstring & key() const { return m_key; }

        ArrangementArea * arrangementArea() const { return m_arrangementArea; }

        using JournalParameters = std::map<std::wstring, std::wstring>;
        ///\brief Record a log at the journal for this ArrangementAreaContent. Later, the
        /// ArrangementAreaContent::onReplayJournal() is called, while replaying the journal.
        void recordJournal(const ArrangementAreaContent::JournalParameters &) const;

        virtual QWidget * qtWidget() = 0;
        virtual void onPostParentChanged();
        virtual void onPostGeometryChanged() = 0;
        virtual void onPostVisibilityChanged() = 0;
        virtual void onPostOpacityChanged();
        virtual void onEvent(ArrangementAreaEvent *) {}
        virtual bool onIsBlank() const { return false; }
        virtual bool onDoesAcceptDrop(DragMove *) const { return false; }
        virtual void onDrop(DragMove *) {}
        virtual bool onReplayJournal(const ArrangementAreaContent::JournalParameters &) { return false; }
        virtual gcmp::OwnerPtr<ArrangementAreaContent>
            clone() const { return nullptr; }

        std::wstring generateKey() const;

        void setEnabled(bool enabled);
        bool isEnabled() const { return m_enabled; }

        const ScaleFactor & scaleFactor() const;

        bool isReconnectingArrangementArea() const { return !m_reasonReconnectingArrangementArea.empty(); }
        void beginToReconnectArrangementAreaDueTo(const std::string &);

    protected:
        virtual void onPostConnectedWithArrangementArea() = 0;
        virtual void onPostReconnectedWithArrangementArea() {
            DBG_WARN(L"Override this virtual method!", L"GMEP", L"2022-09-09");
        }
        virtual void onPreDisconnectedFromArrangementArea() = 0;
        virtual void onPostAbilityChanged() { 
            DBG_WARN(L"Override this virtual method!", L"GMEP", L"2021-05-24");
        }

        bool closeIsolatedWindow(bool wantToRetrieveBeforeClose = false);

        bool isInIsolatedWindow() const;
        bool isInTile() const;

    private:
        friend class ArrangementArea;
        void connectWith(ArrangementArea *);
        void reconnect(const ArrangementArea * const, ArrangementArea *);
        void disconnectFrom(const ArrangementArea * const);
    
        const std::wstring m_key;
        ArrangementArea * m_arrangementArea;
        bool m_enabled;
        std::string m_reasonReconnectingArrangementArea;
    };
    
    class GNUF_BASE_EXPORT ArrangementAreaContentManager final
    {
    private:
        ArrangementAreaContentManager();
        ~ArrangementAreaContentManager();
        
    public:
        static ArrangementAreaContentManager * get();

        typedef std::set<ArrangementAreaContent *> Contents;
        const ArrangementAreaContentManager::Contents & contents() const { return m_contents; }

        ArrangementAreaContent * contentBy(const std::wstring &) const;
        
    private:
        friend class ArrangementAreaContent;
        void    add(ArrangementAreaContent *);
        void remove(ArrangementAreaContent *);
        
        ArrangementAreaContentManager::Contents m_contents;
    };
    
}
